package org.rslai.tcedit.security;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rslai.tcedit.business.RoleService;
import org.rslai.tcedit.domain.Role;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.util.AntUrlPathMatcher;
import org.springframework.security.util.RegexUrlPathMatcher;
import org.springframework.security.util.UrlMatcher;
import org.springframework.web.context.ServletContextAware;

/**
 * @author rslai
 * 
 * @spring.bean id="loadRoleResource" init-method="init"
 */
public class LoadRoleResource implements ServletContextAware, InitializingBean {
	protected Log log = LogFactory.getLog(getClass());

	private UrlMatcher urlMatcher;
    private boolean useAntPath = true;
    private boolean lowercaseComparisons = true;
    
	private ServletContext servletContext;
	private RoleService roleService;

	/**
	 * 设置 useAntPath
	 * @param useAntPath
	 *            useAntPath
	 */
	public void setUseAntPath(boolean useAntPath) {
		this.useAntPath = useAntPath;
	}

	/**
	 * 设置为小写比较
	 * @param lowercaseComparisons
	 */
	public void setLowercaseComparisons(boolean lowercaseComparisons) {
		this.lowercaseComparisons = lowercaseComparisons;
	}

	/**
	 * 实现 ServletContextAware 接口需要的方法，初始化 ServletContext
	 */
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	/**
	 * @spring.property ref="roleService"
	 */
	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}

	/**
	 * 初始化 bean 时执行。先执行 afterPropertiesSet ，再执行 init-method
	 */
	public void afterPropertiesSet() throws Exception {
		// URL 匹配方式 RegexUrlPathMatcher
		this.urlMatcher = new RegexUrlPathMatcher();

		// 如果使用 useAntPath 则改为 AntUrlPathMatcher，默认采用 AntUrlPathMatcher
		if (useAntPath) {
			this.urlMatcher = new AntUrlPathMatcher();
		}

		// 是否设置为小写比较，默认设置为小写比较
		if ("true".equals(lowercaseComparisons)) {
			if (!this.useAntPath) {
				((RegexUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(true);
			}
		} else if ("false".equals(lowercaseComparisons)) {
			if (this.useAntPath) {
				((AntUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(false);
			}
		}
	}

	/**
	 * 初始化 bean 时执行。先执行 afterPropertiesSet ，再执行 init-method
	 */
	public void init() {
		refreshRoleResource();
	}

	/**
	 * 刷新角色可以操作资源的对应信息
	 */
	public void refreshRoleResource() {
		Map<String, List<String>> urlAuthoritiesMap = new HashMap<String, List<String>>();
		Map<String, List<String>> methodAuthoritiesMap = new HashMap<String, List<String>>();
		
		Iterator<Role> it = roleService.query(true).iterator();
		while (it.hasNext()) {
			Role role = it.next();
			for (String permission : role.getUrlPermissionStrList()) {
				if (permission.length() != 0) {
					// 得到 urlAuthoritiesMap 中的角色列表
					List<String> roleNameList = getUrlMapValue(urlAuthoritiesMap, permission);
					if (roleNameList == null) {
						roleNameList = new LinkedList<String>();
						urlAuthoritiesMap.put(permission, roleNameList);
					}
					roleNameList.add(role.getName()); // 添加新的角色到此 url 中
				}
			}

			for (String permission : role.getMethodPermissionStrList()) {
				if (permission.length() != 0) {
					// 得到 methodAuthoritiesMap 中的角色列表
					List<String> roleNameList = getMethodMapValue(methodAuthoritiesMap, permission);
					if (roleNameList == null) {
						roleNameList = new LinkedList<String>();
						methodAuthoritiesMap.put(permission, roleNameList);
					}
					roleNameList.add(role.getName()); // 添加新的角色到此 method 中
				}
			}
		}

		servletContext.removeAttribute("urlAuthorities");
		servletContext.setAttribute("urlAuthorities", urlAuthoritiesMap);

		servletContext.removeAttribute("methodAuthorities");
		servletContext.setAttribute("methodAuthorities", methodAuthoritiesMap);

		if (log.isInfoEnabled()) {
			for (Iterator<Map.Entry<String, List<String>>> iter = urlAuthoritiesMap.entrySet().iterator(); iter.hasNext();) {
				Map.Entry<String, List<String>> entry = iter.next();
				StringBuffer logStr = new StringBuffer();
				logStr.append("URL允许访问角色：");
				logStr.append(entry);
				log.info(logStr.toString());
			}

			for (Iterator<Map.Entry<String, List<String>>> iter = methodAuthoritiesMap.entrySet().iterator(); iter.hasNext();) {
				Map.Entry<String, List<String>> entry = iter.next();
				StringBuffer logStr = new StringBuffer();
				logStr.append("Method允许访问角色：");
				logStr.append(entry);
				log.info(logStr.toString());
			}
		}
	}

	/**
	 * 根据指定的 key 按照 urlMatcher 的查找方式返回 map 中的 Value
	 * @param map map
	 * @param key key
	 * @return
	 */
	private List<String> getUrlMapValue(Map<String, List<String>> map, String key) {
		for (Iterator<Map.Entry<String, List<String>>> iter = map.entrySet().iterator(); iter.hasNext();) {
			Map.Entry<String, List<String>> entry = iter.next();
			String mapKey = entry.getKey();

			if (urlMatcher.pathMatchesUrl(mapKey, key)) {
				return map.get(mapKey);
			}
		}

		return null;
	}

	/**
	 * 根据指定的 key 返回 map 中的 Value (目前方法不支持通配符，如果有需要可以使用urlMatcher支持通配符)
	 * @param map map
	 * @param key key
	 * @return
	 */
	private List<String> getMethodMapValue(Map<String, List<String>> map, String key) {
		return map.get(key);
	}

}